package game.players.states;

import com.uqbar.vainilla.DeltaState;

import utils.Position;
import game.ball.Possessed;
import game.ball.SoccerBall;
import game.players.SoccerPlayer;
import game.players.SoccerPlayerCPU;

public abstract class WithoutBallCPU extends WithoutBall {

	public WithoutBallCPU(SoccerPlayer player) {
		super(player);
	}
	
	@Override
	public void update(DeltaState deltaState) {
		SoccerBall ball = this.getPlayer().getScene().getSoccerBall();
		SoccerPlayerCPU player = (SoccerPlayerCPU) this.getPlayer();
		
		if (this.getPlayer().getScene().isMateOfWithBall(this.getPlayer()) && player.getRefreshCounter() <= 0) {
			SoccerPlayer playerWithBall = ((Possessed) ball.getState()).getPlayer();
			
			if (player.isOutOfHisArea(ball))
				this.returnToHisPosition(player);
			else {
				this.followTheAttack(playerWithBall);
			}
				
			player.resetCounter();
		}
		else {
			if (this.isAtDistanceFromTheBall(ball, 200, 150) && !this.getPlayer().getScene().isMateOfChasingTheBall(this.getPlayer()) && player.getRefreshCounter() <= 0) {
				this.getPlayer().setChasingTheBall(true);
				this.advanceToBall(ball);
				player.resetCounter();
			}
			
			if (player.isOutOfHisArea(ball) && player.getRefreshCounter() <= 0) {
				this.getPlayer().setChasingTheBall(false);
				this.returnToHisPosition(player);
				player.resetCounter();
			}
		}
		
		super.update(deltaState);
		player.setRefreshCounter(player.getRefreshCounter() - 1);
	}
	
	protected void advanceToBall(SoccerBall ball) {
		double vectorI = ball.getX() - this.getPlayer().getX() + this.getPlayer().getFeetWidth();
		double vectorJ = ball.getY() - this.getPlayer().getY() - this.getPlayer().getAppearance().getHeight() + this.getPlayer().getFeetHeight();
		
		double module = Math.sqrt(Math.pow(vectorI, 2) + Math.pow(vectorJ, 2));
		
		double versorI = vectorI / module;
		double versorJ = vectorJ / module;
		
		double advancedX = versorI * this.getPlayer().getMovementSpeed();
		double advancedY = versorJ * this.getPlayer().getMovementSpeed();
		
		if (advancedX >= 0)
			this.changeToRightMoving(advancedX, advancedY);
		else
			this.changeToLeftMoving(advancedX, advancedY);
	}
	
	protected void followTheAttack(SoccerPlayer player) {
		double vectorI = player.getX() + player.getFeetWidth() - this.getPlayer().getX() + this.getPlayer().getFeetWidth();
		double vectorJ = player.getY() - this.getPlayer().getY() - this.getPlayer().getAppearance().getHeight() + this.getPlayer().getFeetHeight();

		double module = Math.sqrt(Math.pow(vectorI, 2) + Math.pow(vectorJ, 2));
		double versorI = vectorI / module;
		double advancedX = versorI * this.getPlayer().getMovementSpeed();
		
		if (this.goesToTheRivalArc(advancedX))
			this.changeToStationaryPosition();
		else
			this.changeToTheRivalArcWith(advancedX, 0);
	}

	protected void returnToHisPosition(SoccerPlayerCPU player) {
		Position position = player.getRelativePosition();
		double vectorI = position.getX() - this.getPlayer().getX() + this.getPlayer().getFeetWidth();
		double vectorJ = position.getY() - this.getPlayer().getY() + this.getPlayer().getAppearance().getHeight() - this.getPlayer().getFeetHeight();

		double module = Math.sqrt(Math.pow(vectorI, 2) + Math.pow(vectorJ, 2));
		
		double versorI = vectorI / module;
		double versorJ = vectorJ / module;
		
		double advancedX = versorI * this.getPlayer().getMovementSpeed();
		double advancedY = versorJ * this.getPlayer().getMovementSpeed();
		
		if (advancedX >= 0)
			this.changeToRightMoving(advancedX, advancedY);
		else
			this.changeToLeftMoving(advancedX, advancedY);
	}
	
	public void takePossession(SoccerBall ball) {
		double advanceX = this.getPlayer().getX() - ball.getX() + ball.getRatio();
		double advanceY = this.getPlayer().getY() + this.getPlayer().getAppearance().getHeight() - ball.getY() - ball.getRatio();
		
		ball.moveNormally(advanceX, advanceY);
		
		ball.setState(new Possessed(this.getPlayer()));
		this.changeToTheRivalArc();
	}

	protected boolean isAtDistanceFromTheBall(SoccerBall ball, double x, double y) {
		return this.getPlayer().getX() - ball.getX() <= x && this.getPlayer().getX() - ball.getX() >= -x
				&& this.getPlayer().getY() - ball.getY() <= y && this.getPlayer().getY() - ball.getY() >= -y * 2;
	}
	
	protected abstract boolean goesToTheRivalArc(double x);
	
	protected abstract void changeToStationaryPosition();
	
	protected abstract void changeToTheRivalArcWith(double advancedX, double advancedY);
	
	protected abstract void changeToTheRivalArc();
	
	protected abstract void changeToLeftMoving(double advancedX, double advancedY);

	protected abstract void changeToRightMoving(double x, double y);

}
